
#include "Dispatcher.h"
#include <sys/select.h>
#include "Channel.h"
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define MAX 1024
struct SelectData
{
    fd_set readset;
    fd_set writeSet;
};

static void *selectinit(); // Dispacherdata
static int selectAdd(struct Channel *channel, struct EventLoop *eventLoop);
static int selectRemove(struct Channel *channel, struct EventLoop *eventLoop);
static int selectModify(struct Channel *channel, struct EventLoop *eventLoop);

static int selectDispatch(struct EventLoop *eventLoop, int timeout);

static int selectClear(struct EventLoop *eventLoop);
static void setFdset(struct Channel *channel, struct SelectData *data);
static void clearFdset(struct Channel *channel, struct SelectData *data);

// 如何和Dispatcher关联
struct Dispatcher SelectDispatcher = {
    selectinit,
    selectAdd,
    selectRemove,
    selectModify,
    selectDispatch,
    selectClear};

static void *selectinit()
{
    struct SelectData *data = (struct SelectData *)malloc(sizeof(struct SelectData));
    FD_ZERO(&data->readset);
    FD_ZERO(&data->writeSet);
    return data;
}
static void setFdSet(struct Channel *channel, struct SelectData *data)
{
    if (channel->event & ReadEvent)
    {
        FD_SET(channel->fd, &data->readset);
    }
    if (channel->event & WriteEvent)
    {
        FD_SET(channel->fd, &data->writeSet);
    }
}
static void clearFdSet(struct Channel *channel, struct SelectData *data)
{
    if (channel->event & ReadEvent)
    {
        FD_CLR(channel->fd, &data->readset);
    }
    if (channel->event & WriteEvent)
    {
        FD_CLR(channel->fd, &data->writeSet);
    }
}
/// @brief
/// @param channel  channel 的读或者写是我们自己定义的，跟linux的不一样
/// @param eventLoop
static int selectAdd(struct Channel *channel, struct EventLoop *eventLoop)
{
    struct SelectData *data = (struct SelectData *)eventLoop->DispatcherData;

    // 判断fd是否超过了最大值
    if (channel->fd >= MAX)
    {
        return -1;
    }
    setFdSet(channel, data);
    return 0;
}

static int selectRemove(struct Channel *channel, struct EventLoop *eventLoop)
{
    struct SelectData *data = (struct SelectData *)eventLoop->DispatcherData;

    clearFdSet(channel, data);
    // 通过channel释放对应的TcpConnection 的资源
    channel->destoryCallBack(channel->arg);
    return 0;
}

static int selectModify(struct Channel *channel, struct EventLoop *eventLoop)
{
    struct SelectData *data = (struct SelectData *)eventLoop->DispatcherData;

    // 这里先后有关系吗？想一想，因为channel-->fd 里面得events是写好了的 ，event也是确定的
    // 某个文件描述德事件
    setFdSet(channel, data);
    clearFdSet(channel, data);

    // 什么时候用poll elect 检测的fd不多 ，大多数是激活的 qq在聊天是激活  qq挂起不激活

    return 0;
}

// 我在想他这里为什什么要进行转换，说传过来的是void* 类型的
static int selectDispatch(struct EventLoop *eventLoop, int timeout)
{
    struct SelectData *data = (struct SelectData *)eventLoop->DispatcherData;

    // int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
    // int count = select(data->fds, data->maxfd + 1, timeout * 1000); // 传进来的事件是ms
    struct timeval tim;
    tim.tv_sec = timeout;
    tim.tv_usec = 0;

    // z这里要对原始数据进行备份,原理是这是一个输入输出型参数 ，假设你输入得是 111111111  但是你只有9好就绪了 返回 000000001 这样你下一次监听得时候只有9好就绪了
    fd_set rdtmp = data->readset;
    fd_set wdtmp = data->writeSet;
    int count = select(MAX, &rdtmp, &wdtmp, NULL, &tim);

    if (count == -1)
    {
        perror("select error");
    }

    // 这个count 只是表示多少个事件就绪了 ，并不能表示这写文件描述符是连续得
    for (int i = 0; i < MAX; ++i)
    {
        if (FD_ISSET(i, &rdtmp))
        {
            // 读事件就绪了，执行回调函数
            eventActivate(eventLoop, i, ReadEvent);
        }

        if (FD_ISSET(i, &wdtmp))
        {
            // 写事件就绪了，执行回调函数
            eventActivate(eventLoop, i, WriteEvent);
        }
    }
    return 0;
}

static int selectClear(struct EventLoop *eventLoop)
{
    struct SelectData *data = (struct SelectData *)eventLoop->DispatcherData;
    // 创建的数组
    free(data);
    return 0;
}


